/*
 *  Copyright (c) M2TK Project. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package m2tk.assistant.app.ui.view;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import m2tk.assistant.app.ui.component.PCRChartBoard;
import m2tk.assistant.app.ui.model.PCRStatsTableModel;
import m2tk.assistant.app.ui.task.AsyncQueryTask;
import m2tk.assistant.app.ui.util.ComponentUtil;
import m2tk.assistant.common.InfoView;
import m2tk.assistant.common.M2TKDatabase;
import m2tk.assistant.common.domain.PCRCheck;
import m2tk.assistant.common.domain.PCRStats;
import m2tk.assistant.common.event.RefreshInfoViewRequest;
import m2tk.assistant.common.ui.RoundPanel;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.Application;
import org.kordamp.ikonli.fluentui.FluentUiRegularAL;
import org.kordamp.ikonli.swing.FontIcon;
import org.pf4j.Extension;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static m2tk.assistant.common.ui.UIConstants.*;

@Extension(ordinal = 3)
public class PCRInfoView extends RoundPanel implements InfoView
{
    private PCRStatsTableModel statsTableModel;
    private PCRChartBoard chartBoard;
    private JSplitPane splitPane;

    private Application application;
    private M2TKDatabase database;
    private EventBus bus;

    private final String viewTitle = "PCR分析";
    private final Icon viewIcon = FontIcon.of(FluentUiRegularAL.CLOCK_24, ICON_SIZE_L, LIGHT_BLUE);
    private volatile long lastTimestamp;
    private static final long MIN_QUERY_INTERVAL_MILLIS = 500;

    public PCRInfoView()
    {
        initUI();
    }

    private void initUI()
    {
        statsTableModel = new PCRStatsTableModel();
        JTable table = createTable();
        table.setModel(statsTableModel);
        table.getTableHeader().setReorderingAllowed(false);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setRowSelectionAllowed(true);
        table.setColumnSelectionAllowed(false);
        table.getSelectionModel().addListSelectionListener(e -> {
            if (e.getValueIsAdjusting())
                return;

            int selectedRow = table.getSelectedRow();
            if (selectedRow == -1)
            {
                hideChartBoard();
            } else
            {
                PCRStats stats = statsTableModel.getStatAtRow(selectedRow);
                queryPCRRecords(stats.getPid());
            }
        });

        DefaultTableCellRenderer leadingRenderer = new DefaultTableCellRenderer();
        leadingRenderer.setHorizontalAlignment(SwingConstants.LEADING);

        TableColumnModel columnModel = table.getColumnModel();
        ComponentUtil.configTableColumn(columnModel, 0, 40, false);                    // 状态
        ComponentUtil.configTableColumn(columnModel, 1, leadingRenderer, 150, false);  // PID
        ComponentUtil.configTableColumn(columnModel, 2, leadingRenderer, 120, false);  // PCR总数
        ComponentUtil.configTableColumn(columnModel, 3, leadingRenderer, 120, false);  // 平均码率
        ComponentUtil.configTableColumn(columnModel, 4, leadingRenderer, 100, false);  // 平均间隔
        ComponentUtil.configTableColumn(columnModel, 5, leadingRenderer, 100, false);  // 最小间隔
        ComponentUtil.configTableColumn(columnModel, 6, leadingRenderer, 100, false);  // 最大间隔
        ComponentUtil.configTableColumn(columnModel, 7, leadingRenderer, 100, false);  // 间隔越界
        ComponentUtil.configTableColumn(columnModel, 8, leadingRenderer, 100, false);  // 平均精度
        ComponentUtil.configTableColumn(columnModel, 9, leadingRenderer, 100, false);  // 最小精度
        ComponentUtil.configTableColumn(columnModel, 10, leadingRenderer, 100, false); // 最大精度
        ComponentUtil.configTableColumn(columnModel, 11, leadingRenderer, 100, false); // 精度越界

        chartBoard = new PCRChartBoard();
        splitPane = createVerticalSplitPane(createScrollPane(table), chartBoard);

        setLayout(new MigLayout("insets 10", "[][grow][]", "[25!][pref!][][grow]"));
        add(new JLabel(viewTitle,
                       FontIcon.of(FluentUiRegularAL.CLOCK_20, ICON_SIZE_S, LIGHT_BLUE),
                       SwingConstants.TRAILING),
            "left, wrap");
        add(separator(), "span 3, grow, wrap");
        add(splitPane, "span 3 2, grow");

        hideChartBoard();

        addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentShown(ComponentEvent e)
            {
                if (database != null)
                    queryPCRStats();
            }
        });
    }

    @Override
    public void setupApplication(Application application)
    {
        this.application = application;
    }

    @Override
    public void setupDataSource(EventBus bus, M2TKDatabase database)
    {
        this.bus = bus;
        this.database = database;

        bus.register(this);
    }

    @Override
    public JComponent getViewComponent()
    {
        return this;
    }

    @Override
    public String getViewTitle()
    {
        return viewTitle;
    }

    @Override
    public Icon getViewIcon()
    {
        return viewIcon;
    }

    @Subscribe
    public void onRefreshInfoViewEvent(RefreshInfoViewRequest event)
    {
        long t1 = System.currentTimeMillis();
        if (t1 - lastTimestamp >= MIN_QUERY_INTERVAL_MILLIS && isShowing())
        {
            queryPCRStats();
            lastTimestamp = System.currentTimeMillis();
        }
    }

    private void queryPCRStats()
    {
        Supplier<List<PCRStats>> query = () -> database.listPCRStats();
        Consumer<List<PCRStats>> consumer = statsTableModel::update;

        AsyncQueryTask<List<PCRStats>> task = new AsyncQueryTask<>(application, query, consumer);
        task.execute();
    }

    private void queryPCRRecords(int stream)
    {
        Supplier<List<PCRCheck>> query = () -> database.getRecentPCRChecks(stream, 1000);
        Consumer<List<PCRCheck>> consumer = checks ->
        {
            chartBoard.update(checks);
            showChartBoard();
        };

        AsyncQueryTask<List<PCRCheck>> task = new AsyncQueryTask<>(application, query, consumer);
        task.execute();
    }

    private void hideChartBoard()
    {
        chartBoard.setVisible(false);
        splitPane.setDividerLocation(1.0);
    }

    private void showChartBoard()
    {
        chartBoard.setVisible(true);
        splitPane.setDividerLocation(0.25);
    }
}
